Introdução¶
A fatoração de matrizes é um algoritmo utilizado em sistemas de recomendação, ele desempenhou um papel importante no resultado da equipe ganhadora do Netflix Grand Prize (Zang et al, 2023). A decomposição de valor singular (SVD) é um método de fatoração de matrizes. Ela ajuda na redução de dimensionalidade, sem eliminar as fontes de informações (MINER et al., 2012).
A fórmula da decomposição de valor singular (SVD) é:
$$M = \sum V^{t}$$
Onde,
$M$ é a matriz original que queremos decompor;
$U$ é matriz singular esquerda (colunas são vetores singulares esquerdos). Colunas U contêm autovetores da matriz $MM^{t}$
$\sum$ é uma matriz diagonal contendo valores singulares (próprios)
$V$ é matriz singular direita (colunas são vetores singulares direitos). $V$ colunas contêm autovetores da matriz $M^{t}M$

Fonte da imagem: Wikipedia
%load_ext pretty_jupyter
Importar bibliotecas¶
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
# confusion_matrix, accuracy_score, precision_score,
# recall_score, f1_score: Funções do scikit-learn
# para calcular métricas de desempenho.
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import BaggingClassifier
import time
from tqdm import tqdm
from sklearn.base import clone
from sklearn.decomposition import TruncatedSVD
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import StandardScaler
import joblib
Carregar arquivos¶
Tabela de apoio¶
catalago = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.3_Datasets_Transformação_parte_3/catalogo.pickle", compression='gzip')
Tabelas para modelagem 1: filmes¶
# Dados de treino
knn_filmes_treino = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.3_Datasets_Transformação_parte_3/knn_filmes_treino.pickle", compression='gzip')
# Dados de teste
knn_filmes_teste = pd.read_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/3.Datasets_Transformação/3.3_Datasets_Transformação_parte_3/knn_filmes_teste.pickle", compression='gzip')
# Olhar tabela de treino para modelagem 1: Filmes
knn_filmes_treino
| title | (2019) | "Great Performances" Cats (1998) | #Alive (2020) | #Female Pleasure (2018) | #Iamhere (2020) | #UNFIT: The Psychology of Donald Trump (2019) | $ (Dollars) (1971) | $5 a Day (2008) | $9.99 (2008) | $ellebrity (Sellebrity) (2012) | ... | Üvegtigris (2001) | Τέλειοι Ξένοι (2016) | Χούλιγκανς: Κάτω τα χέρια απ' τα νιάτα! (1983) | Делай - раз! (1989) | Каменная башка (2008) | Карусель (1970) | Он вам не Димон (2017) | Пес Барбос и необычный кросс (1961) | Я худею (2018) | …And the Fifth Horseman Is Fear (1965) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| userId | |||||||||||||||||||||
| 5 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 15 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 49 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 119 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 134 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 330651 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330661 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330811 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330949 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330963 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
7943 rows × 24326 columns
# Olhar tabela de teste para modelagem 1: Filmes
knn_filmes_teste
| title | #Alive (2020) | $ (Dollars) (1971) | '71 (2014) | '83 (2021) | 'Hellboy': The Seeds of Creation (2004) | 'Round Midnight (1986) | 'Salem's Lot (2004) | 'Til There Was You (1997) | 'burbs, The (1989) | 'night Mother (1986) | ... | tick, tick...BOOM! (2021) | xXx (2002) | xXx: Return of Xander Cage (2017) | xXx: State of the Union (2005) | ¡Three Amigos! (1986) | ¿Quién mató a Bambi? (2013) | À nous la liberté (Freedom for Us) (1931) | Ánimas (2018) | Épouse-moi mon pote (2017) | Ужас, который всегда с тобой (2007) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| userId | |||||||||||||||||||||
| 128 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 172 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 465 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 598 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 919 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 330236 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330321 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330496 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330667 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 330948 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1986 rows × 15496 columns
Modelagem¶
Treinar o SVD¶
# Aplicar SVD
n_components = 20
svd = TruncatedSVD(n_components=n_components) # Reduzir a dimensionalidade
latent_matrix = svd.fit_transform(knn_filmes_treino) # Treinar o SVD
latent_matrix_transpose = svd.components_
# Reconstruir a matriz de avaliações aproximada
reconstructed_matrix = np.dot(latent_matrix, latent_matrix_transpose)
# Similaridade entre usuários
user_similarity = cosine_similarity(latent_matrix)
user_similarity
array([[ 1. , 0.88488888, 0.83560888, ..., 0.13263455,
0.51287916, 0.25578198],
[ 0.88488888, 1. , 0.73380236, ..., -0.04176017,
0.68229894, 0.1340374 ],
[ 0.83560888, 0.73380236, 1. , ..., 0.03963122,
0.41904029, 0.2059464 ],
...,
[ 0.13263455, -0.04176017, 0.03963122, ..., 1. ,
0.11863279, 0.06117318],
[ 0.51287916, 0.68229894, 0.41904029, ..., 0.11863279,
1. , 0.36283311],
[ 0.25578198, 0.1340374 , 0.2059464 , ..., 0.06117318,
0.36283311, 1. ]])
knn_filmes_teste.value_counts().sum()
np.int64(1986)
Fazer a previsão para um userId¶
# Exemplo de função ajustada para usar .iloc se knn_filmes_teste é um DataFrame do Pandas
def predict_rating(user_index, item_index, user_similarity, knn_filmes_teste, knn_filmes_treino):
# Se o usuário já avaliou o filme, retorna a avaliação real
if knn_filmes_teste.iloc[user_index, item_index] != 0:
return knn_filmes_teste.iloc[user_index, item_index]
# Calcula a previsão com base na similaridade entre usuários
predicted_rating = np.dot(user_similarity[user_index], knn_filmes_treino.iloc[:, item_index]) / np.sum(user_similarity[user_index])
return predicted_rating
# Exemplo de uso
user_index = 128
item_index = 3
predicted_rating = predict_rating(user_index, item_index, user_similarity, knn_filmes_teste, knn_filmes_treino)
print(f"Predicted rating for user {user_index} on item {item_index}: {predicted_rating}")
Predicted rating for user 128 on item 3: 0.0001792284916849959
Fazer a previsão para todos userId¶
def predict_all_ratings(user_similarity, knn_filmes_teste, knn_filmes_treino):
predicted_ratings = knn_filmes_teste.copy() # Copia o DataFrame knn_filmes_teste para armazenar as previsões
for user_index in range(knn_filmes_teste.shape[0]):
# Encontra os índices dos filmes não avaliados pelo usuário atual
unrated_indices = np.where(knn_filmes_teste.iloc[user_index, :] == 0)[0]
# Calcula as previsões para os filmes não avaliados
if len(unrated_indices) > 0:
user_sim = user_similarity[user_index]
knn_treino_subset = knn_filmes_treino.iloc[:, unrated_indices]
predicted_ratings.iloc[user_index, unrated_indices] = np.dot(user_sim, knn_treino_subset) / np.sum(user_sim)
return predicted_ratings
from tqdm import tqdm
import time
# Número total de iterações
total_iterations = 100
# Uso do tqdm para criar a barra de progresso
for i in tqdm(range(total_iterations)):
# Simulação de trabalho
#time.sleep(0.1) # Aqui você substitui pelo seu trecho de código
# Chamada da função para prever todas as avaliações
predicted_ratings_df = predict_all_ratings(user_similarity, knn_filmes_teste, knn_filmes_treino)
# Ao finalizar, a barra de progresso será completa
print("Execução completa!")
Execução completa!
# Tabela com as recomendações para todos os usuários
predicted_ratings_df
| title | #Alive (2020) | $ (Dollars) (1971) | '71 (2014) | '83 (2021) | 'Hellboy': The Seeds of Creation (2004) | 'Round Midnight (1986) | 'Salem's Lot (2004) | 'Til There Was You (1997) | 'burbs, The (1989) | 'night Mother (1986) | ... | tick, tick...BOOM! (2021) | xXx (2002) | xXx: Return of Xander Cage (2017) | xXx: State of the Union (2005) | ¡Three Amigos! (1986) | ¿Quién mató a Bambi? (2013) | À nous la liberté (Freedom for Us) (1931) | Ánimas (2018) | Épouse-moi mon pote (2017) | Ужас, который всегда с тобой (2007) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| userId | |||||||||||||||||||||
| 128 | 0.000149 | 0.000142 | 0.000910 | 0.000098 | 0.000135 | 0.000168 | 0.000049 | 0.000013 | 0.000201 | 0.000017 | ... | 0.011577 | 0.002151 | 0.000635 | 0.000461 | 0.000299 | 0.000135 | 0.000020 | 0.000246 | 0.000055 | 0.000048 |
| 172 | 0.000117 | 0.000134 | 0.001026 | 0.000150 | 0.000126 | 0.000148 | 0.000032 | 0.000004 | 0.000271 | 0.000010 | ... | 0.014429 | 0.002467 | 0.000753 | 0.000597 | 0.000287 | 0.000126 | 0.000019 | 0.000338 | 0.000064 | 0.000047 |
| 465 | 0.000160 | 0.000239 | 0.000765 | 0.000144 | 0.000191 | 0.000164 | 0.000025 | 0.000005 | 0.000222 | 0.000015 | ... | 0.014693 | 0.002695 | 0.000790 | 0.000562 | 0.000283 | 0.000098 | 0.000026 | 0.000299 | 0.000073 | 0.000044 |
| 598 | 0.000447 | 0.000466 | 0.000902 | 0.000153 | 0.000454 | 0.000392 | 0.000065 | 0.000113 | 0.000187 | 0.000022 | ... | 0.016987 | 0.005590 | 0.001436 | 0.000401 | 0.000710 | -0.000008 | 0.000066 | 0.000262 | 0.000121 | 0.000127 |
| 919 | 0.000176 | 0.000175 | 0.001303 | 0.000239 | 0.000188 | 0.000205 | 0.000031 | 0.000024 | 0.000323 | 0.000016 | ... | 0.019631 | 0.003365 | 0.001053 | 0.000744 | 0.000325 | 0.000204 | 0.000025 | 0.000331 | 0.000072 | 0.000056 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 330236 | 0.000109 | 0.000296 | 0.000910 | 0.000143 | 0.000202 | 0.000313 | 0.000077 | 0.000053 | 0.000185 | 0.000020 | ... | 0.011580 | 0.002583 | 0.000709 | 0.000253 | 0.000543 | 0.000056 | 0.000025 | 0.000289 | 0.000053 | 0.000079 |
| 330321 | -0.000012 | 0.000312 | 0.001057 | 0.000228 | 0.000204 | 0.000195 | 0.000027 | 0.000014 | 0.000258 | 0.000009 | ... | 0.020154 | 0.003299 | 0.001039 | 0.000770 | 0.000293 | 0.000126 | 0.000026 | 0.000294 | 0.000067 | 0.000049 |
| 330496 | 0.000175 | 0.000254 | 0.001294 | 0.000161 | 0.000214 | 0.000262 | 0.000074 | 0.000029 | 0.000232 | 0.000012 | ... | 0.015922 | 0.002862 | 0.000777 | 0.000559 | 0.000436 | 0.000128 | 0.000025 | 0.000392 | 0.000070 | 0.000070 |
| 330667 | 0.000129 | 0.000206 | 0.000991 | 0.000204 | 0.000152 | 0.000219 | 0.000084 | 0.000036 | 0.000313 | 0.000030 | ... | 0.013308 | 0.002471 | 0.000709 | 0.000489 | 0.000457 | 0.000096 | 0.000027 | 0.000357 | 0.000072 | 0.000073 |
| 330948 | -0.000103 | 0.000044 | 0.000511 | 0.000048 | 0.000074 | 0.000154 | 0.000018 | 0.000019 | 0.000175 | 0.000019 | ... | 0.011471 | 0.001815 | 0.000643 | 0.000453 | 0.000268 | 0.000136 | 0.000012 | 0.000084 | 0.000020 | 0.000041 |
1986 rows × 15496 columns
# Salvar tabela predicted_ratings_df
predicted_ratings_df.to_pickle("C:/0.Projetos/5.Sistema_de_Recomendacao_MovieLens_2/Datasets/6.Modelagem_SVD/predicted_ratings_df.pickle", compression="gzip")
Listagem de recomendações¶
Criar um dataframe com 2 colunas: UserId e uma lista com as recomendações.
n_recomendacoes = 3
# Função para encontrar os top N filmes recomendados para um usuário
def top_recomendacoes(row, n) -> list:
''' Função que encontra as melhores recomendações para cada userId
Args:
- row = linha do DataFrame.
Cada linha representa as recomendações de filme para cada userId.
- n = número de filmes a serem recomendados
Return:
- Retorna uma lista com os "n" valores mais altos em cada.
Ou seja, retorna com as "n" recomendações de filmes.
'''
# Selecionar e retornar os "n" valores mais altos de cada linha
return row.nlargest(n).index.tolist()
#OBS: .index(): Obtemos os nomes dos filmes, ao invés dos valores.
# .tolist(): Criamos uma lista com os nomes dos filmes
# Aplicar a função a cada linha do DataFrame de previsões
recomendacoes = predicted_ratings_df.apply(top_recomendacoes, n=n_recomendacoes, axis=1)
# OBS: apply(... axis=1) -> Aplicar em cada linha
# n = número de recomendações
recomendacoes
userId
128 [The Croods: A New Age (2020), Jungle (2017), ...
172 [The Croods: A New Age (2020), Jungle (2017), ...
465 [10 Things I Hate About You (1999), 21 Jump St...
598 [Lady in Red, The (1979), The Croods: A New Ag...
919 [The Croods: A New Age (2020), Pianist, The (2...
...
330236 [The Croods: A New Age (2020), Lady in Red, Th...
330321 [The Croods: A New Age (2020), Pianist, The (2...
330496 [Event Horizon (1997), High Fidelity (2000), R...
330667 [2001: A Space Odyssey (1968), Blade Runner (1...
330948 [Bad Santa (2003), Due Date (2010), Fast and t...
Length: 1986, dtype: object
# Criar um DataFrame para armazenar as recomendações
df_recomendacoes = pd.DataFrame(recomendacoes.tolist(), index=recomendacoes.index, columns=[f"recomendação_{i+1}" for i in range(n_recomendacoes)])
# Transformar o userId em coluna
df_recomendacoes = df_recomendacoes.reset_index()
df_recomendacoes
| userId | recomendação_1 | recomendação_2 | recomendação_3 | |
|---|---|---|---|---|
| 0 | 128 | The Croods: A New Age (2020) | Jungle (2017) | Pianist, The (2002) |
| 1 | 172 | The Croods: A New Age (2020) | Jungle (2017) | Pianist, The (2002) |
| 2 | 465 | 10 Things I Hate About You (1999) | 21 Jump Street (2012) | 40-Year-Old Virgin, The (2005) |
| 3 | 598 | Lady in Red, The (1979) | The Croods: A New Age (2020) | Pianist, The (2002) |
| 4 | 919 | The Croods: A New Age (2020) | Pianist, The (2002) | Jungle (2017) |
| ... | ... | ... | ... | ... |
| 1981 | 330236 | The Croods: A New Age (2020) | Lady in Red, The (1979) | Jungle (2017) |
| 1982 | 330321 | The Croods: A New Age (2020) | Pianist, The (2002) | Juno (2007) |
| 1983 | 330496 | Event Horizon (1997) | High Fidelity (2000) | Royal Tenenbaums, The (2001) |
| 1984 | 330667 | 2001: A Space Odyssey (1968) | Blade Runner (1982) | Boyhood (2014) |
| 1985 | 330948 | Bad Santa (2003) | Due Date (2010) | Fast and the Furious: Tokyo Drift, The (Fast a... |
1986 rows × 4 columns
df_recomendacoes.isna().sum()
userId 0 recomendação_1 0 recomendação_2 0 recomendação_3 0 dtype: int64
Verificar se o userId assistiu a recomendação¶
Vamos criar uma função chamada assistiu_ou_nao. Esta função vai verificar se os usuários assistiram ou não a alguma das recomendações e em seguida vai retornar 1 (se assistiu), 0 (se não assitiu) e 2 (se o filmes não está no conjunto de teste).
def assistiu_ou_nao(row, df_teste):
# Obtém as recomendações para o usuário atual
recomendacoes = row.drop('userId').values
# Verifica se algum dos filmes recomendados está no df_teste e foi assistido (rating diferente de 0)
for filme in recomendacoes:
if filme in df_teste.columns and df_teste.loc[row['userId'], filme] != 0:
return 1
elif filme not in df_teste.columns:
return 2
#else:
# return 0
# Se nenhum filme recomendado foi assistido, retorna 0
return 0
# Aplicar a função a cada linha do DataFrame de recomendações para criar a coluna dummy
df_recomendacoes['assistiu_recomendacao'] = df_recomendacoes.apply(assistiu_ou_nao, df_teste=knn_filmes_teste, axis=1)
df_recomendacoes
| userId | recomendação_1 | recomendação_2 | recomendação_3 | assistiu_recomendacao | |
|---|---|---|---|---|---|
| 0 | 128 | The Croods: A New Age (2020) | Jungle (2017) | Pianist, The (2002) | 0 |
| 1 | 172 | The Croods: A New Age (2020) | Jungle (2017) | Pianist, The (2002) | 0 |
| 2 | 465 | 10 Things I Hate About You (1999) | 21 Jump Street (2012) | 40-Year-Old Virgin, The (2005) | 1 |
| 3 | 598 | Lady in Red, The (1979) | The Croods: A New Age (2020) | Pianist, The (2002) | 0 |
| 4 | 919 | The Croods: A New Age (2020) | Pianist, The (2002) | Jungle (2017) | 0 |
| ... | ... | ... | ... | ... | ... |
| 1981 | 330236 | The Croods: A New Age (2020) | Lady in Red, The (1979) | Jungle (2017) | 0 |
| 1982 | 330321 | The Croods: A New Age (2020) | Pianist, The (2002) | Juno (2007) | 1 |
| 1983 | 330496 | Event Horizon (1997) | High Fidelity (2000) | Royal Tenenbaums, The (2001) | 1 |
| 1984 | 330667 | 2001: A Space Odyssey (1968) | Blade Runner (1982) | Boyhood (2014) | 1 |
| 1985 | 330948 | Bad Santa (2003) | Due Date (2010) | Fast and the Furious: Tokyo Drift, The (Fast a... | 1 |
1986 rows × 5 columns
Resultados Modelo 1¶
Na etapa anterior, geramos as recomendações, e criamos uma coluna (assistiu_recomendacao) para comparar as recomendações com os filmes assisitidos pelos userId dos dados de teste. Cada linha desta coluna é representada por 0, 1 ou 2.
- 0: significa que nenhum filme da recomendação foi assistido pelo usuário ;
- 1: significa que pelo menos um dos filmes recomendados foi assistido pelo usuário;
- 2: significa que o filme recomendado, não está nos dados de teste. A explicação disso foi dada no tópico acima.
df_recomendacoes['assistiu_recomendacao'].value_counts()
assistiu_recomendacao 1 1078 0 908 Name: count, dtype: int64
Referência Bibliográfica¶
MINER, G. et al. (EDS.). Chapter 11 - Singular Value Decomposition in Text Mining.
Disponível em: https://www.sciencedirect.com/science/article/pii/B9780123869791000396
ZHANG, A. et al.Dive into deep learning. Cambridge, England: Cambridge University Press, 2023.
Disponível em: https://d2l.ai/chapter_recommender-systems/mf.html
